package com.yff.tuan.interceptor;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.yff.tuan.util.ApiConstants;


/**
 * It is used to add the Response-header and stats the api.
 */
public class LoggingInterceptor extends HandlerInterceptorAdapter {

	/** The Constant LOG. */
	private static final Logger LOG = LoggerFactory.getLogger(LoggingInterceptor.class);
	
	/** The Constant QUESTION_CHAR. */
	private static final String QUESTION_CHAR = "?";
	
	/** The Constant CRLF. */
	private static final String CRLF = System.getProperty("line.separator");
	
	/**
	 * common interceptor preHandle
	 * Method Name : preHandle.
	 *
	 * @param request the request
	 * @param response the response
	 * @param handler the handler
	 * @return boolean
	 * @throws Exception the exception
	 * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#preHandle
	 *      (javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception{
		long startTime = System.currentTimeMillis();
		
		String rnd =  (String) request.getAttribute(ApiConstants.RQID);
		StringBuilder apiUrl = new StringBuilder();
		
		LOG.info("[{}]start[{}] : preHandle......", rnd, startTime);

		String servletPath = request.getServletPath();

		try{
			StringBuilder uriSb = new StringBuilder(servletPath);
			String queryString = request.getQueryString();
			if (queryString != null){
				uriSb.append(QUESTION_CHAR);
				uriSb.append(queryString);
			}
			
			StringBuilder logSb = new StringBuilder();
			logSb.append(CRLF);
			logSb.append("**************************************************   REQUEST URL   **********************************************");
			logSb.append(CRLF);
			logSb.append(request.getMethod());
			logSb.append(" ");
			logSb.append(uriSb.toString());
			logSb.append(" ");
			logSb.append(request.getProtocol());
			logSb.append(CRLF);
			
			apiUrl.append(request.getMethod()).append(" ").append(uriSb.toString()).append(" ").append(request.getProtocol());
			
			logSb.append("**************************************************   HEADERS   **************************************************");
			logSb.append(CRLF);
			
			Enumeration<String> allHeaderNames = request.getHeaderNames();
			while (allHeaderNames.hasMoreElements()){
				String headerName = allHeaderNames.nextElement();
				
				Enumeration<String> headerNames = request.getHeaders(headerName);
				while (headerNames.hasMoreElements()){
					String headerValue = headerNames.nextElement();
					logSb.append(headerName);
					logSb.append(" : ");
					logSb.append(headerValue);
					logSb.append(CRLF);
				}
			}

			logSb.append("**************************************************   PARAMS   **************************************************");
			logSb.append(CRLF);
			
			Enumeration<String> paramNames = request.getParameterNames();
			while (paramNames.hasMoreElements()){
				String paramName = paramNames.nextElement();
				
				String[] paramValues = request.getParameterValues(paramName);
				if (paramValues == null || paramValues.length == 0){
					logSb.append(paramName);
					logSb.append(" : ");
					logSb.append(CRLF);
				} else{
					for (String paramValue : paramValues){
						logSb.append(paramName);
						logSb.append(" : ");
						logSb.append(paramValue);
						logSb.append(CRLF);
					}
				}
			}
			logSb.append("****************************************************************************************************************");
			LOG.info(logSb.toString());
		} catch (Exception ex){
			LOG.error("", ex);
		}

		if (servletPath.startsWith("/errors")){
			return true;
		}
		
		request.setAttribute("preHandleStartTime", startTime);
		request.setAttribute("apiUrl", apiUrl.toString());
		return super.preHandle(request, response, handler);
	}
	
	/**
	 * common interceptor postHandle
	 * Method Name : postHandle.
	 *
	 * @param request the request
	 * @param response the response
	 * @param handler the handler
	 * @param modelAndView the model and view
	 * @return void
	 * @throws Exception the exception
	 * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#postHandle
	 *      (javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse, java.lang.Object,
	 *      org.springframework.web.servlet.ModelAndView)
	 */
	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception{
		long startTime = (Long) request.getAttribute("preHandleStartTime");
		String rnd =  (String) request.getAttribute(ApiConstants.RQID); 
		String apiUrl=  (String) request.getAttribute("apiUrl"); 
		long endTime = System.currentTimeMillis();
		
		String time = Long.toString(endTime - startTime);
		LOG.info("API:[{}] Response:{} [{}]end[{}] : postHandle...{} ms", new Object[]{apiUrl,200,rnd, endTime, time});
		
		super.postHandle(request, response, handler, modelAndView);
	}

	/**
	 * common interceptor postHandle
	 * Method Name : postHandle.
	 *
	 * @param request the request
	 * @param response the response
	 * @param handler the handler
	 * @param ex the ex
	 * @return void
	 * @throws Exception the exception
	 * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#
	 *      afterCompletion(javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse, java.lang.Object,
	 *      java.lang.Exception)
	 */
	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception{
		
		long startTime = (Long) request.getAttribute("preHandleStartTime");
		String rnd =  (String) request.getAttribute(ApiConstants.RQID); 
		String apiUrl=  (String) request.getAttribute("apiUrl"); 
		long endTime = System.currentTimeMillis();
		
		String time = Long.toString(endTime - startTime);
		LOG.info("API:[{}] Response:{} [{}]end[{}] : afterCompletion...{} ms", new Object[]{apiUrl,200,rnd, endTime, time});

		super.afterCompletion(request, response, handler, ex);
	}
}